﻿using System;
using System.Linq;

using JetBrains.ReSharper.Psi;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.ReSharper.Psi.CSharp.Tree;

namespace FinlogiK.ReSharperContrib
{
	internal static class ArrangeStaticQualifierHelper
	{
		#region Methods

		internal static void AddStaticQualifier(IReferenceExpression referenceExpression)
		{
			IDeclaredElement referencedElement = referenceExpression.Reference.Resolve().DeclaredElement;
			IClass targetClass = referencedElement.GetContainingType() as IClass;

			if (targetClass == null)
			{
				throw new InvalidOperationException("Containing type of the reference expression should be a class.");
			}

			string qualifier = ArrangeStaticQualifierHelper.BuildClassQualifierString(targetClass);

			CSharpElementFactory factory = CSharpElementFactory.GetInstance(referenceExpression.GetPsiModule());
			IReferenceExpression qualifierExpression = factory.CreateReferenceExpression(qualifier);
			referenceExpression.SetQualifierExpression(qualifierExpression);
		}

		internal static bool IsReferenceToStaticFieldOrMethodWithoutQualifier(IReferenceExpression referenceExpression)
		{
			bool result = false;

			IDeclaredElement declaredElement = referenceExpression.Reference.Resolve().DeclaredElement;

			if (ArrangeStaticQualifierHelper.IsStaticFieldOrMethod(declaredElement))
			{
				result = (referenceExpression.QualifierExpression == null);
			}

			return result;
		}

		private static string BuildClassQualifierString(IClass targetClass)
		{
			string qualifier = targetClass.ShortName;

			if (targetClass.TypeParameters.Length > 0)
			{
				string[] genericArgumentNames = targetClass.TypeParameters.Select(t => t.ShortName).ToArray();
				qualifier += "<" + string.Join(", ", genericArgumentNames) + ">";
			}

			return qualifier;
		}

		private static bool IsStaticFieldOrMethod(IDeclaredElement element)
		{
			bool result;

			IField field = element as IField;

			if (field == null)
			{
				IMethod method = element as IMethod;
				result = ((method != null) && method.IsStatic);
			}
			else
			{
				result = field.IsStatic;
			}

			return result;
		}

		#endregion
	}
}